﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BST250301TestStand.Models.Helpers
{
    internal class DataTranslate
    {
        /// <summary>
        /// 对给定的 x 数组中的每个元素，在 a 数组中找到它所在的区间 [a[i], a[i+1])，
        /// 然后计算 b 数组中对应位置元素的平均值 (b[i] + b[i+1]) / 2。
        /// </summary>
        /// <param name="a">输入值数组 (必须是有序的，升序)。</param>
        /// <param name="b">输出值数组 (与 a 长度相同)。</param>
        /// <param name="x">要查找的目标值数组。</param>
        /// <returns>计算得到的平均值数组 y (与 x 长度相同)。</returns>
        public static double[] CalculateSegmentAverages(double[] a, double[] b, double[] x)
        {
            // 1. 基础校验
            if (a == null || b == null || x == null || a.Length != b.Length || a.Length < 2)
            {
                throw new ArgumentException("输入数组 a 和 b 必须具有相同长度且长度至少为 2。");
            }

            double[] y = new double[x.Length];

            // 2. 遍历 x 数组中的每一个目标值
            for (int j = 0; j < x.Length; j++)
            {
                double x_target = x[j];

                // 检查边界：如果目标值在 a 的范围之外，处理方式（这里返回边界点的平均值或抛出异常）
                if (x_target < a[0] || x_target > a[a.Length - 1])
                {
                    // 边界处理示例：如果超出范围，返回最近边界段的平均值
                    if (x_target < a[0])
                    {
                        y[j] = (b[0] + b[1]) / 2.0;
                        continue;
                    }
                    else // x_target >= a[a.Length - 1] 
                    {
                        // 最后一个区间：a[N-2] 和 a[N-1]
                        int lastIndex = a.Length - 1;
                        y[j] = (b[lastIndex - 1] + b[lastIndex]) / 2.0;
                        continue;
                    }
                }

                // 3. 查找区间 [a[i], a[i+1])
                // 使用线性搜索查找 i，使得 a[i] <= x_target < a[i+1]
                for (int i = 0; i < a.Length - 1; i++)
                {
                    if (x_target >= a[i] && x_target < a[i + 1])
                    {
                        // 4. 提取对应的 b 值并计算平均值
                        double b_start = b[i];
                        double b_end = b[i + 1];

                        y[j] = (b_start + b_end) / 2.0;
                        break; // 找到区间后，跳出内层循环
                    }

                    // 特殊处理：如果 x_target 恰好是 a 数组的最后一个元素 a[N-1]
                    if (i == a.Length - 2 && x_target == a[a.Length - 1])
                    {
                        // 最后一个点被视为落在最后一个区间 [a[N-2], a[N-1]] 内
                        double b_start = b[i];
                        double b_end = b[i + 1];

                        y[j] = (b_start + b_end) / 2.0;
                        break;
                    }
                }
            }
            return y;
        }
        /// <summary>
        /// 计算 List<double> 中对称位置元素的平均值。
        /// </summary>
        /// <param name="data">原始的 List<double> 数据。</param>
        /// <returns>包含对称平均值（以及中间元素，如果列表长度为奇数）的 List<double>。</returns>
        public static List<double> CalculateSymmetricAverages(List<double> data)
        {
            if (data == null || data.Count == 0)
            {
                return new List<double>();
            }

            List<double> result = new List<double>();
            int n = data.Count;

            // 需要配对的次数 (列表长度的一半，向下取整)
            int halfLength = n / 2; // C#中的整数除法会自动向下取整

            // 1. 计算对称位置的平均值
            for (int i = 0; i < halfLength; i++)
            {
                // i 是从左边开始的索引
                int symmetricIndex = n - 1 - i; // 对称位置的索引 (从右边开始)

                double average = (data[i] + data[symmetricIndex]) / 2.0;
                result.Add(average);
            }

            // 2. 如果列表长度为奇数，添加中间元素
            if (n % 2 != 0)
            {
                // 中间元素的索引
                int middleIndex = halfLength;
                result.Add(data[middleIndex]);
            }

            return result;
        }
        /// <summary>
        /// 获取字节中指定位置的位值
        /// </summary>
        /// <param name="data">目标字节</param>
        /// <param name="index">位索引（0-7，从右到左）</param>
        /// <returns>返回 true 表示该位为 1，false 表示为 0</returns>
        public static bool GetBit(byte data, int index)
        {
            if (index < 0 || index > 7)
                throw new ArgumentOutOfRangeException(nameof(index), "索引必须在 0 到 7 之间");

            return (data & (1 << index)) != 0;
        }
        /// <summary>
        /// 设置报文位数据
        /// </summary>
        /// <param name="canData"></param>
        /// <param name="bitvalue"></param>
        /// <param name="startbyte"></param>
        /// <param name="startbit"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentException"></exception>
        public static byte[] SetBitValue(byte[] canData, byte bitvalue, int startbyte, int startbit)
        {
            if (canData == null || canData.Length < 8)
            {
                throw new ArgumentException($"CAN 报文长度必须是 {8} 字节。");
            }
            try
            {
                byte targetByte = canData[startbyte];
                byte controlValue = bitvalue;
                int startbit2byte = startbyte % 8;
                byte setMask = (byte)(1 << startbit2byte);
                byte clearMask = (byte)(setMask ^ 0xFF);
                setMask = (byte)(controlValue << startbit2byte);
                targetByte = (byte)(targetByte | setMask);
                canData[startbyte] = targetByte;
            }
            catch (Exception)
            {
            }
            return canData;
        }

        /// <summary>
        /// 将指定的值写入到 byte[] 指定位位置（Intel 小端位序）
        /// </summary>
        public static byte[] WriteBits(byte[] buffer, int startBit, int bitLength, uint value)
        {
            for (int i = 0; i < bitLength; i++)
            {
                int bitPos = startBit + i;
                int byteIndex = bitPos / 8;
                int bitIndex = bitPos % 8;

                if (byteIndex >= buffer.Length)
                    throw new IndexOutOfRangeException();

                int bitVal = (int)((value >> i) & 0x1);

                if (bitVal == 1)
                    buffer[byteIndex] |= (byte)(1 << bitIndex);
                else
                    buffer[byteIndex] &= (byte)~(1 << bitIndex);
            }
            return buffer;
        }
        /// <summary>
        /// 字符串转byte数组
        /// </summary>
        /// <param name="hexString"></param>
        /// <returns></returns>
        public static byte[] Str2ByteArr(string hexString)
        {
            try
            {

                // 去除空格并分割为字符串数组
                byte[] bytes = hexString
                    .Split(' ', StringSplitOptions.RemoveEmptyEntries) // 按空格分割
                    .Select(s => Convert.ToByte(s, 16))                // 每个字符串转为byte
                    .ToArray();                                        // 转成byte数组

                return bytes;

            }
            catch (Exception)
            {
                return null;
            }
        }
        /// <summary>
        /// 将 byte 数组中指定字节的指定位设置为 1 (ON)。
        /// 使用位或运算 (|) 实现。
        /// </summary>
        /// <param name="data">要操作的 byte 数组。</param>
        /// <param name="byteIndex">目标字节在数组中的索引。</param>
        /// <param name="bitIndex">目标位在该字节中的索引 (0-7)。</param>
        public static void SetBit(byte[] data, int byteIndex, int bitIndex)
        {
            if (byteIndex < 0 || byteIndex >= data.Length || bitIndex < 0 || bitIndex > 7)
            {
                throw new ArgumentOutOfRangeException("索引超出范围。");
            }

            // 创建设置掩码：例如，要设置 Bit 4，掩码为 00010000 (0x10)
            byte setMask = (byte)(1 << bitIndex);

            // 使用 | (按位或)：将目标位设置为 1，不影响其他位。
            // 原值 | 掩码 = 新值
            data[byteIndex] |= setMask;
        }

        /// <summary>
        /// 将 byte 数组中指定字节的指定位设置为 0 (OFF)。
        /// 使用位与运算 (&) 和取反 (~) 实现。
        /// </summary>
        /// <param name="data">要操作的 byte 数组。</param>
        /// <param name="byteIndex">目标字节在数组中的索引。</param>
        /// <param name="bitIndex">目标位在该字节中的索引 (0-7)。</param>
        public static void ClearBit(byte[] data, int byteIndex, int bitIndex)
        {
            if (byteIndex < 0 || byteIndex >= data.Length || bitIndex < 0 || bitIndex > 7)
            {
                throw new ArgumentOutOfRangeException("索引超出范围。");
            }

            // 1. 创建设置掩码 (Set Mask)：例如，Bit 4 的 Set Mask 是 00010000
            int setMaskInt = (1 << bitIndex);

            // 2. 创建清除掩码 (Clear Mask)：对 Set Mask 取反
            // 使用 unchecked 绕过编译器对常量负数转换的检查
            // 00010000 的 8 位取反是 11101111
            byte clearMask = unchecked((byte)~setMaskInt);

            // 使用 & (按位与)：目标位与 0 相与得 0，其他位与 1 相与保持不变。
            // 原值 & 清除掩码 = 新值
            data[byteIndex] &= clearMask;
        }

        /// <summary>
        /// 读取 byte 数组中指定字节的指定位的值 (True/False)。
        /// </summary>
        /// <param name="data">要操作的 byte 数组。</param>
        /// <param name="byteIndex">目标字节在数组中的索引。</param>
        /// <param name="bitIndex">目标位在该字节中的索引 (0-7)。</param>
        /// <returns>该位的值 (True=1, False=0)</returns>
        public static bool GetBit(byte[] data, int byteIndex, int bitIndex)
        {
            if (byteIndex < 0 || byteIndex >= data.Length || bitIndex < 0 || bitIndex > 7)
            {
                throw new ArgumentOutOfRangeException("索引超出范围。");
            }

            byte checkMask = (byte)(1 << bitIndex);

            // 使用 & (按位与)：只有当目标位是 1 时，结果才不为 0。
            // (原值 & 掩码) != 0 就是该位为 1
            return (data[byteIndex] & checkMask) != 0;
        }

        /// <summary>
        /// 打印 byte 数组的十六进制和二进制表示
        /// </summary>
        public static void PrintData(byte[] data)
        {
            Console.WriteLine($"Hex: {BitConverter.ToString(data)}");
            Console.WriteLine($"Binary: {string.Join(" ", data.Select(b => Convert.ToString(b, 2).PadLeft(8, '0')))}");
        }
        static void test()
        {
            // 模拟一个 4 字节的 CAN 报文
            byte[] canData = new byte[4] { 0x00, 0x01, 0xFF, 0x00 };
            Console.WriteLine("--- 初始状态 ---");
            PrintData(canData);
            // Byte 1 (索引 1) 的初始值是 0x01 (00000001)

            Console.WriteLine("\n--- 1. 设置位 (SetBit) ---");
            // 将 Byte 1 (0x01) 的 Bit 4 设置为 1 (使能 PTO)
            // 00000001 | 00010000 = 00010001 (0x11)
            SetBit(canData, 1, 4);
            Console.WriteLine("设置 Byte 1, Bit 4 为 1:");
            PrintData(canData);

            Console.WriteLine("\n--- 2. 读取位 (GetBit) ---");
            bool ptoEnable = GetBit(canData, 1, 4);
            Console.WriteLine($"Byte 1, Bit 4 (PTO Enable) 的当前值: {ptoEnable}"); // True

            Console.WriteLine("\n--- 3. 清除位 (ClearBit) ---");
            // 将 Byte 1 (0x11) 的 Bit 4 设置为 0 (禁用 PTO)
            // 清除掩码: 11101111 (0xEF)
            // 00010001 & 11101111 = 00000001 (0x01)
            ClearBit(canData, 1, 4);
            Console.WriteLine("清除 Byte 1, Bit 4 为 0:");
            PrintData(canData);

            bool ptoEnableAfterClear = GetBit(canData, 1, 4);
            Console.WriteLine($"Byte 1, Bit 4 (PTO Enable) 的当前值: {ptoEnableAfterClear}"); // False
        }
        /// <summary>
        /// 1. 开启开关：使用按位或 (|)
        /// </summary>
        /// <param name="bitIndex">要开启的位的索引 (0-7)</param>
        public static byte TurnOnSwitch(byte statusByte,int bitIndex)
        {
            // 1 << bitIndex 创建一个设置掩码（Set Mask），只有目标位是 1
            byte setMask = (byte)(1 << bitIndex);

            // 按位或 (|): 任何位与 1 进行或运算，结果为 1。其他位与 0 或运算，保持不变。
            statusByte |= setMask;
            return statusByte;
        }

        /// <summary>
        /// 2. 关闭开关：使用按位与 (&) 和按位取反 (~)
        /// </summary>
        /// <param name="bitIndex">要关闭的位的索引 (0-7)</param>
        public static byte TurnOffSwitch(byte statusByte, int bitIndex)
        {
            // 1. 创建设置掩码 (Set Mask): 目标位为 1，其他位为 0
            int setMaskInt = (1 << bitIndex);

            // 2. 创建清除掩码 (Clear Mask): 对 Set Mask 取反
            // 使用 unchecked 绕过编译器对常量负数转换的检查
            byte clearMask = unchecked((byte)~setMaskInt);

            // 按位与 (&): 目标位与 0 进行与运算，结果为 0。其他位与 1 与运算，保持不变。
            statusByte &= clearMask;
            return statusByte;
        }

        /// <summary>
        /// 3. 切换开关状态：使用按位异或 (^)
        /// </summary>
        /// <param name="bitIndex">要切换的位的索引 (0-7)</param>
        public static byte ToggleSwitch(byte statusByte, int bitIndex)
        {
            // 创建切换掩码（Toggle Mask），与 Set Mask 相同
            byte toggleMask = (byte)(1 << bitIndex);

            // 按位异或 (^): 目标位与 1 异或，状态反转（0变1，1变0）。其他位与 0 异或，保持不变。
            statusByte ^= toggleMask;
            return statusByte;
        }

        /// <summary>
        /// 4. 读取开关状态：使用按位与 (&)
        /// </summary>
        /// <param name="bitIndex">要读取的位的索引 (0-7)</param>
        /// <returns>该位是否为 True (1)</returns>
        public static  bool IsSwitchOn(byte statusByte, int bitIndex)
        {
            byte checkMask = (byte)(1 << bitIndex);

            // 按位与 (&): 只有当目标位为 1 时，(statusByte & checkMask) 的结果才不是 0。
            return (statusByte & checkMask) != 0;
        }
    }
}
